//
// Created by zengao on 2022/12/29.
//

#ifndef C100_ASTNODE_H
#define C100_ASTNODE_H

#include <memory>
#include <list>

namespace C100 {
    class AstVisitor;

    class AstNode {
    public:
        virtual ~AstNode() {}

        virtual void accept(AstVisitor *visitor) {};
    };

    class Var {
    public:
        std::string_view name;
        int offset;
    };

    class ProgramNode : public AstNode {
    public:
        std::list<std::shared_ptr<AstNode>> stmts;
        std::list<std::shared_ptr<Var>> localVars;

        void accept(AstVisitor *visitor) override;
    };

    class ExprStmtNode : public AstNode {
    public:
        std::shared_ptr<AstNode> Lhs;

        void accept(AstVisitor *visitor) override;
    };

    class IfStmtNode : public AstNode {
    public:
        std::shared_ptr<AstNode> Cond{nullptr};
        std::shared_ptr<AstNode> Then{nullptr};
        std::shared_ptr<AstNode> Else{nullptr};

        void accept(AstVisitor *visitor) override;
    };

    enum class BinaryOperator {
        Add,
        Sub,
        Mul,
        Div,
        Equal,
        PipeEqual,
        Greater,
        GreaterEqual,
        Lesser,
        LesserEqual
    };

    class BlockStmtNode : public AstNode {
    public:
        std::list<std::shared_ptr<AstNode>> stmts;

        void accept(AstVisitor *visitor) override;
    };

    class BinaryNode : public AstNode {
    public:
        BinaryOperator binOp;
        std::shared_ptr<AstNode> Lhs;
        std::shared_ptr<AstNode> Rhs;

        void accept(AstVisitor *visitor) override;
    };

    class ConstantNode : public AstNode {
    public:
        int value;

        void accept(AstVisitor *visitor) override;
    };

    class AssignExprNode : public AstNode {
    public:
        std::shared_ptr<AstNode> Lhs;
        std::shared_ptr<AstNode> Rhs;

        void accept(AstVisitor *visitor) override;
    };

    class VarExprNode : public AstNode {
    public:
        std::shared_ptr<Var> varObj;

        void accept(AstVisitor *visitor) override;
    };

    class AstVisitor {
    public:
        virtual ~AstVisitor() {};

        virtual void visitorProgramNode(ProgramNode *node) {};

        virtual void visitorExprStmtNode(ExprStmtNode *node) {};

        virtual void visitorIfStmtNode(IfStmtNode *node) {};

        virtual void visitorBlockStmtNode(BlockStmtNode *node) {};

        virtual void visitorBinaryNode(BinaryNode *node) {};

        virtual void visitorConstantNode(ConstantNode *node) {};

        virtual void visitorVarExprNode(VarExprNode *node) {};

        virtual void visitorAssignExprNode(AssignExprNode *pNode) {}
    };
}

#endif //C100_ASTNODE_H
